#pragma semicolon 1
#include <sourcemod>
#include <cstrike>
#include <sdktools>
#include <sdkhooks>
#include <colors>
#include <PowerupsX>
#define PREFIX "{olive}PowerupsX {default}>{green} "

new AbilityBig;
new AbilitySmall;
new bool:AbilitySizeMode[MAXPLAYERS+1] = { false, ... };

public OnPluginStart()
{
	NativeIncStart();
	
	AbilityBig = PX_RegisterAbility("AbilityBig");
	PX_SetAbilityName(AbilityBig,"Titan");
	PX_SetAbilityDescription(AbilityBig,"Level 1: Size Multiplier: 1.0+Level/10.");
	PX_SetAbilityUsage(AbilityBig,"Level 1: Makes You Larger. Level 5: Knife: Toggles Current Size.");
	PX_SetAbilityMaxLevel(AbilityBig,7);
	
	AbilitySmall = PX_RegisterAbility("AbilitySmall");
	PX_SetAbilityName(AbilitySmall,"Pint-Size");
	PX_SetAbilityDescription(AbilitySmall,"Level 1: Size Multiplier: 1.0-Level/10. Level 5: Knife: Toggles Current Size.");
	PX_SetAbilityUsage(AbilitySmall,"Level 1: Makes You Smaller. Level 5: Knife: Toggles Current Size.");
	PX_SetAbilityMaxLevel(AbilitySmall,7);
	
	HookEvent("player_spawn",Event_PlayerSpawn);
	HookEvent("weapon_fire",Event_WeaponFire);
}

ResizePlayer(Client, Float:fScale)
{
	SetEntPropFloat(Client, Prop_Send, "m_flModelScale", fScale);
	SetEntPropFloat(Client, Prop_Send, "m_flStepSize", 18.0 * fScale);
	SetEntPropFloat(Client, Prop_Send, "m_flLaggedMovementValue", Clamp(1 * fScale,0.7,100));
	SetEntityGravity(Client, Pow(fScale,-1.0));
}

public OnClientPutInServer(Client)
{
    SDKHook(Client, SDKHook_OnTakeDamage, OnTakeDamage);
}

public Action:OnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype)
{
	new Level = PX_GetLevel(attacker, PX_GetAbility(attacker));
	if(AbilitySizeMode[victim] == true)
	{	
		if(PX_GetAbility(victim) == AbilityBig)
		{
			damage *= 1.0-float(Level/10);
		}
		else if(PX_GetAbility(victim) == AbilitySmall)
		{
			damage *= 1.0+float(Level/10);
		}
	}
	return Plugin_Continue;
}

public Action:Event_PlayerSpawn(Handle:event, const String:name[],bool:dontBroadcast)
{
	new userid = GetClientOfUserId(GetEventInt(event,"userid"));
	
	if(PX_GetAbility(userid) == AbilityBig || PX_GetAbility(userid) == AbilitySmall)
	{
		AbilitySizeMode[userid] = false;
		ResizePlayer(userid, 1.0);
	}
}

public PXF_OnAbilityRemoved(Client, Ability)
{
	if(Ability == AbilityBig || Ability == AbilitySmall)
	{
		ResizePlayer(Client,1.0);
		AbilitySizeMode[Client] = false;
	}
}

public PXF_OnLevelChanged(Client, Ability, NewLevel)
{
	if(AbilitySizeMode[Client] == true)
	{
		if(Ability == AbilityBig)
		{
			ResizePlayer(Client, 1.0+float(NewLevel/10));
		}
		else if(Ability == AbilitySmall)
		{
			ResizePlayer(Client, 1.0-float(NewLevel/10));
		}
	}
}

public OnClientDisconnect(Client)
{
	AbilitySizeMode[Client] = false;
}

public Action:Event_WeaponFire(Handle:event, const String:name[],bool:dontBroadcast)
{
	decl String:sWeapon[30];
	GetEventString(event,"weapon",sWeapon,30);
	new userid = GetClientOfUserId(GetEventInt(event,"userid"));
	new Level = PX_GetLevel(userid, PX_GetAbility(userid));
	
	if(StrEqual(sWeapon, "knife"))
	{
		if(PX_GetAbility(userid) == AbilityBig)
		{
			if(IsFakeClient(userid))
			{
				return;
			}
			
			if(AbilitySizeMode[userid] == false)
			{
				new Float:Add = float(Level/10);
				ResizePlayer(userid, 1.0+Add);
				PrintCenterText(userid, "Grown!");
				AbilitySizeMode[userid] = true;
			}
			else
			{
				ResizePlayer(userid, 1.0);
				PrintCenterText(userid, "Shrunk!");
				AbilitySizeMode[userid] = false;
			}
		}
		else if(PX_GetAbility(userid) == AbilitySmall)
		{
			if(IsFakeClient(userid))
			{
				return;
			}
			
			if(AbilitySizeMode[userid] == false)
			{
				new Float:Sub = float(Level/10);
				ResizePlayer(userid, 1.0-Sub);
				PrintCenterText(userid, "Shrunk!");
				AbilitySizeMode[userid] = true;
			}
			else
			{
				ResizePlayer(userid, 1.0);
				PrintCenterText(userid, "Grown!");
				AbilitySizeMode[userid] = false;
			}
		}
	}
}

stock any:Clamp(any:value, any:min, any:max)
{
	if (value < min) 
	{
		value = min;
	}
	if (value > max) 
	{
		value = max;
	}
	return value;
}